package suncertify.gui;

import java.util.Arrays;

import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;

import suncertify.contractors.Contractor;
import suncertify.db.Data;

/**
 * This class represents the view in the MVC pattern, it provides a tabular view of the model data. The model part of
 * the MVC pattern is represented by an array of {@link Contractor} objects.
 * 
 * <p>
 * This class extends the abstract {@link AbstractTableModel} class and overrides the methods that provide swing with
 * all the data it needs to build the contractors <code>JTable</code>. This class provides all the functionality needed
 * to show an array of {@link Contractor} objects in a {@link JTable} swing component.
 * 
 * @see AbstractTableModel
 * @see ClientApplicationFrameController
 * 
 */
class ContractorsJTableView extends AbstractTableModel implements ContractorsViewInterface {

    /**
     * Automatic generated serialization version ID.
     */
    private static final long serialVersionUID = 5165L;

    /**
     * Array of contractor field names, each element corresponds to one column in the <code>jTableView</code> .
     */
    private String[] columnNames = Contractor.getPropertyNames();

    /**
     * Array of contractor objects to be shown in the <code>jTableView</code>. This array is the model part of the MVC.
     */
    private Contractor[] contractorsArray = null;

    /**
     * The control were the <code>contractorsArray</code> objects are shown. This is the view part of the MVC.
     */
    private JTable jTableView = null;

    /**
     * Represents the selected row in the <code>jTableView</code>. Minus value means no row is selected.
     */
    private int selectedRow = -1;

    /**
     * Constructs the class using the provided parameters. The input parameters are stored in member variables. The
     * <code>contractors</code> array is sorted alphabetically in an ascending order. The class itself is assigned to
     * the tables model using {@link JTable#setModel(javax.swing.table.TableModel)}, this call causes the table
     * component to be published with data.
     * 
     * @param jTable
     *            The table object that will be published with the contractors.
     * @param contractors
     *            The contractor objects to be shown in the table.
     */
    public ContractorsJTableView(JTable jTable, Contractor[] contractors) {

	this.jTableView = jTable;
	this.contractorsArray = contractors;

	Arrays.sort(this.contractorsArray);

	this.jTableView.setModel(this);

	TableColumnModel tableColumnModel = this.jTableView.getColumnModel();

	DefaultTableCellRenderer tableCellRenderer = new DefaultTableCellRenderer();
	tableCellRenderer.setHorizontalAlignment(DefaultTableCellRenderer.RIGHT);

	tableColumnModel.getColumn(Data.FIELD_INDEX_SIZE).setCellRenderer(tableCellRenderer);
	tableColumnModel.getColumn(Data.FIELD_INDEX_RATE).setCellRenderer(tableCellRenderer);
	tableColumnModel.getColumn(Data.FIELD_INDEX_OWNER).setCellRenderer(tableCellRenderer);

    }

    /**
     * Returns the contractor object that corresponds to the selected row in the table.
     * 
     * @return Null if no row is selected, otherwise the selected contractor object is returned.
     * 
     */
    public Contractor getSelectedContractor() {

	// get selected row
	this.selectedRow = this.jTableView.getSelectedRow();

	// check if we have a valid selected row.
	if (this.selectedRow < 0) {
	    return null;
	}

	return this.contractorsArray[(int) this.selectedRow];
    }

    /**
     * Causes the <code>JTable</code> component to draw itself and to be synchronized with the data in the
     * {@link Contractor} object(s). Usually called when the data of a contractor object that is shown in the table
     * changes. This function makes sure the selected row remains selected after the table is repainted.
     */
    public void refreshSelectedContractor() {

	this.jTableView.tableChanged(new TableModelEvent(this.jTableView.getModel()));

	// restore the row selection
	if (this.selectedRow > 0) {
	    this.jTableView.getSelectionModel().setSelectionInterval(this.selectedRow, this.selectedRow);
	}
    }

    /**
     * Returns the count of the table columns. The count of the table columns represents the public fields of the
     * <code>Contractor</code> object.
     * 
     * @return Number of columns.
     * 
     */
    public int getColumnCount() {
	return columnNames.length;
    }

    /**
     * Returns the name of the column referred to by the <code>column</code> parameter.
     * 
     * @param column
     *            The index of the column which is from 0 to less than {@link #getColumnCount()}
     * @return The column name.
     * 
     */
    public String getColumnName(int column) {

	return columnNames[column];
    }

    /**
     * Returns the table's number of rows. The number of rows is equivalent to the contractors array length parameter in
     * the constructor.
     * 
     * @return Number of rows.
     * 
     */
    public int getRowCount() {
	return this.contractorsArray.length;
    }

    /**
     * Returns the value that is shown in the specified row and column in the table. Each row represents one contractor,
     * each column corresponds to one contractor property/field, e.g. column 0 shows {@link Contractor#getName()},
     * column 1 shows {@link Contractor#getLocation()} and so on.
     * 
     * @param row
     *            The row in which the value is to be shown.
     * @param column
     *            The column in which the value is to be shown.
     * @return The string that will be shown.
     * 
     */
    public Object getValueAt(int row, int column) {

	Contractor contractor = this.contractorsArray[row];

	return contractor.getDisplayValueByIndex(column);
    }

    /**
     * Empty implementation of {@link AbstractTableModel#setValueAt(Object, int, int)}. This function contains no code.
     * 
     * @param obj
     *            See {@link AbstractTableModel#setValueAt(Object, int, int)}
     * @param row
     *            See {@link AbstractTableModel#setValueAt(Object, int, int)}
     * @param column
     *            See {@link AbstractTableModel#setValueAt(Object, int, int)}
     * 
     */
    public void setValueAt(Object obj, int row, int column) {
    }

    /**
     * Determines if the current cell referred to by <code>row</code> and <code>column</code> is editable.
     * 
     * @param row
     *            Row of the current cell.
     * @param column
     *            Column of the current cell.
     * @return False for all cells.
     * 
     */
    public boolean isCellEditable(int row, int column) {
	return false;
    }
}